# ============================================================
# * Copyright © hk. 2022-2025. All rights reserved.
# * File name: CMakeLists.txt
# * Author   : 苏木
# * Date     : 2025-05-22
# * Version  : 
# * Description: cmake version 3.16.3
# ============================================================
## https://cmake.com.cn/cmake/help/latest/guide/tutorial/index.html
## https://cmake.org/cmake/help/latest/

# 指定 CMake 的最低版本要求
# --------------------------------------------------
cmake_minimum_required(VERSION 3.10)


# 设置项目名称和使用的编程语言
# --------------------------------------------------
project(SPROJECT C)


# 指定可执行程序和源文件
# --------------------------------------------------
add_executable(app_demo.out main.c)

# 函数定义，当定义函数后，调用的方式与任何其他CMake命令完全相同。
# --------------------------------------------------
# function(name [arg1 [arg2 [...]]])
#  # Function body (i.e. commands) ...
# endfunction()

# 1. 函数可以带参数也可以不带
message(STATUS "==> no param function")
function(print_me)
	message(STATUS "Hello from inside a function")
	message(STATUS "All done")
endfunction()
# Called like so:
print_me()
message("")

# 对于函数来说，每个参数都是一个CMake变量，例如：可以作为变量在if()语句中进行判断。
# 调用函数时，有几个参数就要传几个，不然会报错
message(STATUS "==> param function")
function(print param1 param2)
	message(STATUS "Hello from inside a function!")
	if(DEFINED param1)
		message("Macro param1 is a defined variable!param1=${param1}")
	else()
		message("Macro param1 is NOT a defined variable!")
	endif()
	if(DEFINED param2)
		message("Macro param2 is a defined variable!param2=${param2}")
	else()
		message("Macro param2 is NOT a defined variable!")
	endif()
	message(STATUS "All done")
endfunction()
# Called like so:
print(123 a)
message("")


# 2. 命名参数之外，函数和宏还有一组自定义的变量
# ARGC 传递给函数的参数总数。它计算已命名参数和给定的其他未命名参数的数量。
# ARGV 这是一个列表变量，包含传递给函数的每个参数，包括指定的参数和未命名参数。
# ARGN 和ARGV类似,也是一个列表，只包含命名参数以外的参数(即可选的、未命名参数)
# 例如函数只有一个参数为arg，但是传入了a b c三个参数，那么ARGC=3 ARGV=a ARGN=b;c。
message(STATUS "==> function ARGC and ARGV and ARGN")
function(print_arg param1 param2)
	message(STATUS "Hello from inside a function!ARGC=${ARGC} ARGV=${ARGV} ARGN=${ARGN}")
	message(STATUS "All done")
endfunction()
# Called like so:
print_arg(123 a b c) # ARGC=4 ARGV=123;a;b;c ARGN=b;c
message("")

# 3. 函数内定义或修改的变量对函数外的同名变量没有影响。就变量而言，函数本质上是一个沙箱。
#    由于函数引入了变量作用域，因此似乎没有简单的方法将信息传递回调用者。那我要是想在函数中修改某个函数外的变量怎么办？
message(STATUS "==> 函数的作用域demo")

function(dangerous_function)
    set(result "MODIFIED")  # 不会污染调用者的作用域
	message(STATUS "[dangerous_function]result=${result}")  # 输出: ORIGINAL
endfunction()

function(safe_function)
    set(result "ORIGINAL")
	message(STATUS "[safe_function] before dangerous_function result=${result}")  # 输出: ORIGINAL
    dangerous_function()
    message(STATUS "[safe_function] after dangerous_function result=${result}")  # 输出: ORIGINAL
endfunction()
safe_function()
message("")
# 输出如下：
# -- ==> 函数的作用域demo
# -- [safe_function] before dangerous_function result=ORIGINAL
# -- [dangerous_function]result=MODIFIED
# -- [safe_function] after dangerous_function result=ORIGINAL

# 3.1 其实set()命令的PARENT_SCOPE关键字可以用于修改调用作用域中的变量，而不是函数中的局部变量。虽然这与从函数返回值不同，但它确实允许将一个值(或多个值)传递回调用者。
function(dangerous_function1)
    set(result1 "MODIFIED" PARENT_SCOPE)  # 会修改调用者中的变量
	message(STATUS "[dangerous_function]result1=${result1}")  # 输出: ORIGINAL
endfunction()

function(safe_function1)
    set(result1 "ORIGINAL")
	message(STATUS "[safe_function] before dangerous_function result1=${result1}")  # 输出: ORIGINAL
    dangerous_function1()
    message(STATUS "[safe_function] after dangerous_function result1=${result1}")  # 输出: ORIGINAL
endfunction()
safe_function1()
message("")
# 输出如下：
# -- [safe_function] before dangerous_function result1=ORIGINAL
# -- [dangerous_function]result1=ORIGINAL
# -- [safe_function] after dangerous_function result1=MODIFIED

